package queue;

import java.util.LinkedList;
import java.util.Queue;
import java.util.Stack;

public class practice_3_17 {
    /*
    * 622. 设计循环队列
    *设计你的循环队列实现。 循环队列是一种线性数据结构，其操作表现基于 FIFO（先进先出）
    * 原则并且队尾被连接在队首之后以形成一个循环。它也被称为“环形缓冲器”。
    *循环队列的一个好处是我们可以利用这个队列之前用过的空间。在一个普通队列里，一旦一个队列满了，
    * 我们就不能插入下一个元素，即使在队列前面仍有空间。但是使用循环队列，我们能使用这些空间去存储新的值。
    *你的实现应该支持如下操作：
    *MyCircularQueue(k): 构造器，设置队列长度为 k 。
    * Front: 从队首获取元素。如果队列为空，返回 -1 。
    * Rear: 获取队尾元素。如果队列为空，返回 -1 。
    * enQueue(value): 向循环队列插入一个元素。如果成功插入则返回真。
    * deQueue(): 从循环队列中删除一个元素。如果成功删除则返回真。
    * isEmpty(): 检查循环队列是否为空。
    *isFull(): 检查循环队列是否已满。
    */
    static class MyCircularQueue {
        private int[] data;     //存储元素的数组
        private int first = 0;  //队头
        private int last = 0;   //队尾
        private int size = 0;   //队列中有效元素个数
        //构造能容纳k个元素的循环队列
        public MyCircularQueue(int k) {
            data = new int[k];
        }
        //入队
        public boolean enQueue(int value) {
            //检查循环队列是否满了
            if(isFull()){
                return false;   //满了，入队失败，返回false
            }
            //循环队列还有空间，将元素入队
            data[last] = value;
            last++;
            //注意队尾等于数组长度，将队尾重置为0
            if(last == data.length){
                last = 0;
            }
            //增加有效元素个数
            size++;
            return true;    //入队成功，返回true
        }
        //出队
        public boolean deQueue() {
            //检查队列是否为空
            if(isEmpty()){
                return false;   //空队列，出队失败，返回false
            }
            first++;    //出队，直接将队头后移一位，进行逻辑删除
            //注意队头是否等于数组长度
            if(first == data.length){
                first = 0;  //等于数组长度，将其置为0
            }
            //有效元素个数建1
            size--;
            //出队成功，返回true
            return true;
        }
        //获取队头元素
        public int Front() {
            //检查队列是否为空，空说明队列没有元素，获取队头元素失败
            if(isEmpty()){
                return -1;
            }
            return data[first];
        }
        //获取队尾元素
        public int Rear() {
            //检查队列是否为空，空说明队列没有元素，获取队尾元素失败
            if(isEmpty()){
                return -1;
            }
            //注意队尾是否为0
            if(last == 0){
                return data[data.length - 1];
            }else{
                return data[last - 1];
            }
        }
        //判空
        public boolean isEmpty() {
            //有效元素个数为0，则为空，否则不是空队列
            if(size == 0){
                return true;
            }
            return false;
        }
        //判满
        public boolean isFull() {
            //有效元素个数等于数组的容量，则为满，返回true，否则，返回false
            if(size == data.length){
                return true;
            }
            return false;
        }
    }

//    232. 用栈实现队列
//    请你仅使用两个栈实现先入先出队列。队列应当支持一般队列支持的所有操作（push、pop、peek、empty）：
//    实现 MyQueue 类：
//    void push(int x) 将元素 x 推到队列的末尾
//    int pop() 从队列的开头移除并返回元素
//    int peek() 返回队列开头的元素
//    boolean empty() 如果队列为空，返回 true ；否则，返回 false
//    说明：
//    你 只能 使用标准的栈操作 —— 也就是只有 push to top, peek/pop from top, size, 和 is empty 操作是合法的。
//    你所使用的语言也许不支持栈。你可以使用 list 或者 deque（双端队列）来模拟一个栈，只要是标准的栈操作即可。

    static class MyQueue {
        Stack<Integer> stackIn;     //入队栈
        Stack<Integer> stackOut;    //出队栈
        //构造函数
        public MyQueue() {
            stackIn = new Stack<>();
            stackOut = new Stack<>();
        }
        //入队
        public void push(int x) {
            stackIn.push(x);
        }
        //出队
        public int pop() {
            //出队栈为空，则将入队栈的元素转移到出队栈
            if(stackOut.isEmpty()){
                while(!stackIn.isEmpty())
                    stackOut.push(stackIn.pop());
            }
            //出队栈为空，则该队列为空，出队失败，返回-1
            if(stackOut.isEmpty()){
                return -1;
            }else{  //出队栈非空，说明队列中有元素，直接出队
                return stackOut.pop();
            }
        }
        //获取栈顶元素
        public int peek() {
            //出队栈为空，则将入队栈的元素转移到出队栈
            if(stackOut.isEmpty()){
                while(!stackIn.isEmpty())
                    stackOut.push(stackIn.pop());
            }
            //经过上面转以后，出队栈为空，则该队列为空，出队失败，返回-1
            if(stackOut.isEmpty()){
                return -1;
            }else{  //出队栈非空，说明队列中有元素，直接出队，返回出队栈的栈顶元素
                return stackOut.peek();
            }
        }
        //判空
        public boolean empty() {
            //两个栈均为空，则队列为空
            return stackIn.isEmpty() && stackOut.isEmpty();
        }
    }

    /*
    225. 用队列实现栈
    请你仅使用两个队列实现一个后入先出（LIFO）的栈，并支持普通栈的全部四种操作（push、top、pop 和 empty）。
    实现 MyStack 类：
    void push(int x) 将元素 x 压入栈顶。
    int pop() 移除并返回栈顶元素。
    int top() 返回栈顶元素。
    boolean empty() 如果栈是空的，返回 true ；否则，返回 false 。
    注意：
    你只能使用队列的标准操作 —— 也就是 push to back、peek/pop from front、size 和 is empty 这些操作。
    你所使用的语言也许不支持队列。 你可以使用 list （列表）或者 deque（双端队列）来模拟一个队列 , 只要是标准的队列操作即可。
    */
    static class MyStack {
        Queue<Integer> queueIn;     //入栈队列
        Queue<Integer> queueHelp;   //辅助队列（该队列负责转移元素，经过操作后，该队列均为空）

        //构造函数
        public MyStack() {
            queueIn = new LinkedList<>();
            queueHelp = new LinkedList<>();
        }

        //入栈
        public void push(int x) {
            //直接将元素放进入栈队列
            queueIn.offer(x);
        }

        //出栈
        public int pop() {
            //将size-1个元素转移到辅助队列，剩余1个就是栈顶元素
            for (int i = queueIn.size(); i > 1; i--) {
                queueHelp.offer(queueIn.poll());
            }
            //记录栈顶元素
            int ret = queueIn.poll();
            //将辅助队列中的元素转移到入栈队列
            while (!queueHelp.isEmpty()) {
                queueIn.offer(queueHelp.poll());
            }
            //返回栈出栈元素
            return ret;
        }

        //获取栈顶元素
        public int top() {
            //将size-1个元素转移到辅助队列，剩余1个就是栈顶元素
            for (int i = queueIn.size(); i > 1; i--) {
                queueHelp.offer(queueIn.poll());
            }
            //记录栈顶元素
            int ret = queueIn.poll();
            while (!queueHelp.isEmpty()) {
                queueIn.offer(queueHelp.poll());
            }
            //将栈顶元素放进入栈队列
            queueIn.offer(ret);
            //返回栈出栈元素
            return ret;
        }

        //判空
        public boolean empty() {
            //入栈队列为空，则栈为空
            return queueIn.isEmpty();
        }
    }

    public static void main(String[] args) {
        System.out.println();
    }
}
